/**
 * 函数模块 - 提供函数式编程相关工具
 * 借鉴Lodash和Ramda的函数处理理念
 */

/**
 * 防抖函数
 * @param {Function} func 要防抖的函数
 * @param {number} wait 等待时间（毫秒）
 * @param {boolean} immediate 是否立即执行
 * @returns {Function} 防抖后的函数
 */
export function debounce(func, wait = 300, immediate = false) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  let timeout;
  return function(...args) {
    const later = () => {
      timeout = null;
      if (!immediate) func.apply(this, args);
    };

    const callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);

    if (callNow) func.apply(this, args);
  };
}

/**
 * 节流函数
 * @param {Function} func 要节流的函数
 * @param {number} wait 等待时间（毫秒）
 * @param {Object} options 选项
 * @returns {Function} 节流后的函数
 */
export function throttle(func, wait = 300, options = {}) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  let timeout;
  let previous = 0;
  const { leading = true, trailing = true } = options;

  return function(...args) {
    const now = Date.now();

    if (!previous && !leading) previous = now;

    const remaining = wait - (now - previous);

    if (remaining <= 0 || remaining > wait) {
      if (timeout) {
        clearTimeout(timeout);
        timeout = null;
      }
      previous = now;
      func.apply(this, args);
    } else if (!timeout && trailing) {
      timeout = setTimeout(() => {
        previous = !leading ? 0 : Date.now();
        timeout = null;
        func.apply(this, args);
      }, remaining);
    }
  };
}

/**
 * 缓存函数结果
 * @param {Function} func 要缓存的函数
 * @param {Function} resolver 缓存键解析器
 * @returns {Function} 带缓存的函数
 */
export function memoize(func, resolver) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  const cache = new Map();

  function memoized(...args) {
    const key = resolver ? resolver.apply(this, args) : JSON.stringify(args);

    if (cache.has(key)) {
      return cache.get(key);
    }

    const result = func.apply(this, args);
    cache.set(key, result);
    return result;
  }

  memoized.cache = cache;
  return memoized;
}

/**
 * 延迟执行函数
 * @param {Function} func 要延迟的函数
 * @param {number} wait 延迟时间（毫秒）
 * @param {...any} args 函数参数
 * @returns {number} 定时器ID
 */
export function delay(func, wait = 0, ...args) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  return setTimeout(() => func.apply(null, args), wait);
}

/**
 * 函数组合（从右到左）
 * @param {...Function} funcs 要组合的函数
 * @returns {Function} 组合后的函数
 */
export function compose(...funcs) {
  if (funcs.length === 0) return arg => arg;
  if (funcs.length === 1) return funcs[0];

  return funcs.reduce((a, b) => (...args) => a(b(...args)));
}

/**
 * 函数管道（从左到右）
 * @param {...Function} funcs 要管道的函数
 * @returns {Function} 管道后的函数
 */
export function pipe(...funcs) {
  if (funcs.length === 0) return arg => arg;
  if (funcs.length === 1) return funcs[0];

  return funcs.reduce((a, b) => (...args) => b(a(...args)));
}

/**
 * 函数柯里化
 * @param {Function} func 要柯里化的函数
 * @param {number} arity 参数数量
 * @returns {Function} 柯里化后的函数
 */
export function curry(func, arity = func.length) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  return function curried(...args) {
    if (args.length >= arity) {
      return func.apply(this, args);
    }

    return function(...nextArgs) {
      return curried.apply(this, args.concat(nextArgs));
    };
  };
}

/**
 * 占位符符号
 */
export const _ = Symbol('placeholder');

/**
 * 偏函数应用
 * @param {Function} func 原函数
 * @param {...any} partialArgs 部分参数
 * @returns {Function} 偏应用后的函数
 */
export function partial(func, ...partialArgs) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  return function(...args) {
    const finalArgs = [];
    let argIndex = 0;

    for (let i = 0; i < partialArgs.length; i++) {
      if (partialArgs[i] === _) {
        finalArgs.push(args[argIndex++]);
      } else {
        finalArgs.push(partialArgs[i]);
      }
    }

    // 添加剩余参数
    while (argIndex < args.length) {
      finalArgs.push(args[argIndex++]);
    }

    return func.apply(this, finalArgs);
  };
}

/**
 * 只执行一次的函数
 * @param {Function} func 原函数
 * @returns {Function} 只执行一次的函数
 */
export function once(func) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  let called = false;
  let result;

  return function(...args) {
    if (!called) {
      called = true;
      result = func.apply(this, args);
    }
    return result;
  };
}

/**
 * 限制函数执行次数
 * @param {number} n 最大执行次数
 * @param {Function} func 原函数
 * @returns {Function} 限制执行次数的函数
 */
export function before(n, func) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  let count = 0;
  let result;

  return function(...args) {
    if (++count < n) {
      result = func.apply(this, args);
    }
    return result;
  };
}

/**
 * 在执行指定次数后才开始执行的函数
 * @param {number} n 需要执行的次数
 * @param {Function} func 原函数
 * @returns {Function} 处理后的函数
 */
export function after(n, func) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  let count = 0;

  return function(...args) {
    count++;
    if (count >= n) {
      return func.apply(this, args);
    }
  };
}

/**
 * 函数重试
 * @param {Function} func 要重试的函数
 * @param {number} times 重试次数
 * @param {number} delay 重试间隔（毫秒）
 * @returns {Promise} Promise对象
 */
export function retry(func, times = 3, delay = 1000) {
  return new Promise((resolve, reject) => {
    let attempts = 0;

    function attempt() {
      attempts++;

      try {
        const result = func();

        if (result instanceof Promise) {
          result
            .then(resolve)
            .catch(error => {
              if (attempts >= times) {
                reject(error);
              } else {
                setTimeout(attempt, delay);
              }
            });
        } else {
          resolve(result);
        }
      } catch (error) {
        if (attempts >= times) {
          reject(error);
        } else {
          setTimeout(attempt, delay);
        }
      }
    }

    attempt();
  });
}

/**
 * 函数超时控制
 * @param {Function} func 要控制的函数
 * @param {number} timeout 超时时间（毫秒）
 * @returns {Function} 带超时控制的函数
 */
export function withTimeout(func, timeout = 5000) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  return function(...args) {
    return Promise.race([
      new Promise((resolve, reject) => {
        try {
          const result = func.apply(this, args);
          if (result instanceof Promise) {
            result.then(resolve).catch(reject);
          } else {
            resolve(result);
          }
        } catch (error) {
          reject(error);
        }
      }),
      new Promise((_, reject) => {
        setTimeout(() => reject(new Error('Function timeout')), timeout);
      })
    ]);
  };
}

/**
 * 翻转函数参数顺序
 * @param {Function} func 原函数
 * @returns {Function} 翻转参数后的函数
 */
export function flip(func) {
  if (typeof func !== 'function') {
    throw new TypeError('Expected a function');
  }

  return function(...args) {
    return func.apply(this, args.reverse());
  };
}

/**
 * 否定函数结果
 * @param {Function} predicate 断言函数
 * @returns {Function} 否定后的函数
 */
export function negate(predicate) {
  if (typeof predicate !== 'function') {
    throw new TypeError('Expected a function');
  }

  return function(...args) {
    return !predicate.apply(this, args);
  };
}

/**
 * 创建总是返回指定值的函数
 * @param {any} value 要返回的值
 * @returns {Function} 常量函数
 */
export function constant(value) {
  return function() {
    return value;
  };
}

/**
 * 身份函数（返回第一个参数）
 * @param {any} value 输入值
 * @returns {any} 输入值本身
 */
export function identity(value) {
  return value;
}

/**
 * 空操作函数
 */
export function noop() {
  // 什么都不做
}

/**
 * 检查是否为函数
 * @param {any} value 要检查的值
 * @returns {boolean} 是否为函数
 */
export function isFunction(value) {
  return typeof value === 'function';
}

/**
 * 函数流（从左到右执行）
 * @param {...Function} funcs 要执行的函数
 * @returns {Function} 流函数
 */
export function flow(...funcs) {
  if (funcs.length === 0) return identity;
  if (funcs.length === 1) return funcs[0];

  return function(...args) {
    let result = funcs[0].apply(this, args);
    for (let i = 1; i < funcs.length; i++) {
      result = funcs[i].call(this, result);
    }
    return result;
  };
}

/**
 * 函数流（从右到左执行）
 * @param {...Function} funcs 要执行的函数
 * @returns {Function} 流函数
 */
export function flowRight(...funcs) {
  if (funcs.length === 0) return identity;
  if (funcs.length === 1) return funcs[0];

  return function(...args) {
    let result = funcs[funcs.length - 1].apply(this, args);
    for (let i = funcs.length - 2; i >= 0; i--) {
      result = funcs[i].call(this, result);
    }
    return result;
  };
}
